
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <mpi.h>
#include <time.h>
#include "TextManipulator.h"

int verificaPrimo(int n);

int main(int argc, char *argv[]){

	int i, j, k, rc, num, num1, num2, rank;
	clock_t iniciopalin, inicioprimo, fimpalin, fimprimo;
	double  tempopalin = 0, tempoprimo = 0;
	int size, namesize, n1, n2, resp13, resp24;
	int palin1 = 0, palin2 = 0, palinT, primo1 = 0, primo2 = 0, primoT;
	int source1 = 1, source2 = 2, source3 = 3, source4 = 4, tag11 = 1, tag12 = 2, tag21 = 3, tag22 = 4, tag13 = 5, tag24 = 6;
	int dest0  = 0, dest1 = 1, dest2 = 2, dest3 = 3, dest4 = 4;
	char *straux = NULL;
	char **palavra = NULL, computerName[50];
	unsigned long int npalavras;
	MPI_Status Stat;

	/*Verifica se o programa foi chamdo corretamente*/
	if(argc != 2) {
		printf("Usage: <program> <path_file>\n");
        	return 1;
    	}
	else if(InitializeStructFile(argv[1])) {
	        printf("ERROO!!\n");
		return 1;
    	}

	/*Regiao paralela*/
	rc = MPI_Init(&argc, &argv);
	if(rc == MPI_SUCCESS){
		MPI_Comm_size(MPI_COMM_WORLD, &num);/*nro de maquinas*/
		MPI_Comm_rank(MPI_COMM_WORLD, &rank);/*nro da maquina atual*/
		MPI_Get_processor_name(computerName, &namesize);/*nome do computador*/
		printf("%s: processo: %d de %d\n", computerName, rank, num);
		
	    	
		if(rank == 0){
			
			MPI_Recv(&palin1, 1, MPI_INT, source1, tag11, MPI_COMM_WORLD, &Stat);/*nro de palindromos de rank = 1*/
			MPI_Recv(&primo1, 1, MPI_INT, source1, tag12, MPI_COMM_WORLD, &Stat);/*qntdade de nro primos de rank = 1*/
			MPI_Recv(&palin2, 1, MPI_INT, source2, tag21, MPI_COMM_WORLD, &Stat);/*nro de palindromos de rank = 2*/
			MPI_Recv(&primo2, 1, MPI_INT, source2, tag22, MPI_COMM_WORLD, &Stat);/*qtdade de nros primos de rank = 2*/
			
			palinT = palin1 + palin2;
			primoT = primo1 + primo2;
			
			printf("palindromos: %d\n", palinT);
			printf("primo: %d\n", primoT);
			
		
		}/*fim rank == 0*/
		
		/*verifica se e primo*/
		else if (rank == 3){
			num1 = 0;
			do{
				/*recebo o nro*/
				MPI_Recv(&num1, 1, MPI_INT, source1, tag13, MPI_COMM_WORLD, &Stat);
				/**/
				if(num1 != -1){
					num1 = verificaPrimo(num1);
					
					/*envia a resposta*/
					MPI_Send(&num1, 1, MPI_INT, dest1, tag13, MPI_COMM_WORLD);			
				}
						
			}while((num1 != -1));/*se receber -1 significa que acabou*/
			printf("terminou [%s]\n", computerName);
		}/*fim else rank == 3*/

		/*verifica se e primo*/
		else if(rank == 4){
			do{
				MPI_Recv(&num2, 1, MPI_INT, source2, tag24, MPI_COMM_WORLD, &Stat);
					/**/
				if(num2 != -1){
					num2 = verificaPrimo(num2);
					MPI_Send(&num2, 1, MPI_INT, dest2, tag24, MPI_COMM_WORLD);			
				}
			}while(num2 != -1);
			printf("terminou [%s]\n", computerName);
		}/*fim else rank == 4*/
			
		else{		
			/*Aloca a matriz com as palavras*/   	 	
		    	ResetFlags();
		    	palavra = malloc(AMOUNTW_THREAD*sizeof(char*));
			for(i = 0; i < AMOUNTW_THREAD; i++)
				palavra[i] = malloc(WORDSIZE*sizeof(char));	

			npalavras = ReturnWords(palavra); /*Obtem a quantidade de palavras na matriz*/

			if(rank == 1){
				/*straux ira conter a string inversa*/
				straux = (char*)malloc(sizeof(char)*WORDSIZE);
				for(i = 0; i < npalavras/2; i++){	
					size = strlen(palavra[i]) - 1;
			
					if(size < WORDSIZE){
						iniciopalin = clock();
						for(j = 0; j < (size+1); j++)
							straux[j] = palavra[i][size-j];
						straux[j] = '\0';

						/*verifica se sao palindromos */
						if(strcmp(straux, palavra[i]) == 0){
							fimpalin = clock();
							tempopalin = tempopalin + 1000 * (fimpalin - iniciopalin)/((double)CLOCKS_PER_SEC);
							
							palin1++;
							inicioprimo = clock();
							//printf("[%s] eh palindromo\n", palavra[i]);
							n1 = 0;
							for(k = 0; k < (size+1); k++){
								n1 = (int) palavra[i][k] + n1;
							}
							
							/*envia e recebe a resposta para saber se eh primo*/
							MPI_Send(&n1, 1, MPI_INT, dest3, tag13, MPI_COMM_WORLD);
							MPI_Recv(&resp13, 1, MPI_INT, source3, tag13, MPI_COMM_WORLD, &Stat);
							fimprimo = clock();
							tempoprimo = tempoprimo + 1000 * (fimprimo - inicioprimo)/((double)CLOCKS_PER_SEC);
							if(resp13)
								primo1++;
						}/*fim if palindromo*/
						else
							tempopalin = tempopalin + 1000 * (fimpalin - iniciopalin)/((double)CLOCKS_PER_SEC);
					}/*fim if*/
					
				}/*fim for*/
				

				n1 = -1;
				MPI_Send(&n1, 1, MPI_INT, dest3, tag13, MPI_COMM_WORLD);/*envio -1 p/ rank 4 (significa q acabou as palavras)*/
				/*envia a quantidade  de palindromos e primos*/				
				MPI_Send(&palin1, 1, MPI_INT, dest0, tag11, MPI_COMM_WORLD);
				MPI_Send(&primo1, 1, MPI_INT, dest0, tag12, MPI_COMM_WORLD);
				printf("processo 1 trabalhou em %lu palavras em %.2f segundos\n", npalavras/2, tempopalin);
				printf("processo 1 verificou %d vezes se era primo em %.2f segundos\n", palin1, tempoprimo);
				
				printf("terminou [%s]\n", computerName);
			
				free(straux);
				
			}/*fim if rank == 1*/
			
		
			else if(rank == 2){
				/*straux ira conter a string inversa*/
				straux = (char*)malloc(sizeof(char)*WORDSIZE);
				for(i = npalavras/2; i < npalavras; i++){	
					size = strlen(palavra[i]) - 1;
							
					if(size < WORDSIZE){
						iniciopalin = clock();
						for(j = 0; j < (size+1); j++)
							straux[j] = palavra[i][size-j];
						straux[j] = '\0';

						/*verifica se sao palindromos */
						if(strcmp(straux, palavra[i]) == 0){
							fimpalin = clock();
							tempopalin = tempopalin + 1000 * (fimpalin - iniciopalin)/((double)CLOCKS_PER_SEC);

							palin2++;
							inicioprimo = clock();
							/*printf("\"%s\" eh palindromo\n", palavra[i]);*/
							n2 = 0;
							for(k = 0; k < (size+1); k++){
								n2 = (int) palavra[i][k] + n2;
							}
							/*envia e recebe a resposta para saber se eh primo*/
							MPI_Send(&n2, 1, MPI_INT, dest4, tag24, MPI_COMM_WORLD);			
							MPI_Recv(&resp24, 1, MPI_INT, source4, tag24, MPI_COMM_WORLD, &Stat);
							fimprimo = clock();
							tempoprimo = tempoprimo + 1000 * (fimprimo - inicioprimo)/((double)CLOCKS_PER_SEC);
						
							if(resp24)
								primo2++;
								
						}/*fim if de palindromo*/
						else
							tempopalin = tempopalin + 1000 * (fimpalin - iniciopalin)/((double)CLOCKS_PER_SEC);
					}/*fim if*/
				}/*fim for*/
				
				n2 = -1;
				MPI_Send(&n2, 1, MPI_INT, dest4, tag24, MPI_COMM_WORLD); /*envio -1 p/ rank 4 (significa q acabou as palavras)*/
				/*envia a quantidade  de palindromos e primos*/
				MPI_Send(&palin2, 1, MPI_INT, dest0, tag21, MPI_COMM_WORLD);
				MPI_Send(&primo2, 1, MPI_INT, dest0, tag22, MPI_COMM_WORLD);
				printf("processo 2 trabalhou em %lu palavras em %.2f segundos\n", (npalavras - npalavras/2), tempopalin);
				printf("processo 2 verificou %d vezes se era primo em %.2f segundos\n", palin2, tempoprimo);
				
				printf("terminou [%s]\n", computerName);			
				free(straux);
			}/*fim else rank == 2*/
		}/*fim else*/
	} /*regiao paralela*/
	MPI_Finalize();
	return EXIT_SUCCESS;
}/*fim main*/

int verificaPrimo(int n)
{
    int i, j, Upper, Div, Aux, lsPrm[9999];

     lsPrm[2]=1;
     for(i=3; i<=n; i+=2)
     {
        lsPrm[i]=1;
        lsPrm[i + 1] = 0;
     }


 for(i=2; i*i<= n; i++)
   if(lsPrm[i])
   {
     for(j = 2*i; j <= n; j +=i)
       lsPrm[j] = 0;
   }


  if(lsPrm[n])
    return 1;
  else
    return 0;
}
